<template>
  <div id="app">
    <div class="chat-background"></div>
    <div class="chat-box">
      <div class="bar"></div>
      <div class="left">
        <div class="title">会话列表
          <!-- <i class="tip">99</i> -->
        </div>
        <div class="list">
          <div class="card">
            <div class="pic">
              <img src="@/assets/images/app/avatar.png" alt="" />
            </div>
            <div class="content">
              <p class="name">短语音生成工具</p>
              <p class="message">
                <!-- 语音消息短语音识别工具短语音识别工具短语音识别工具短语音识别工具 -->
              </p>
            </div>
            <div class="tip">
              <!-- <i class="time">09:40</i> -->
              <!-- <i class="num">99</i> -->
            </div>
          </div>
        </div>
      </div>
      <div class="chat-none" style="display:none">
        <p>--- 请选择会话 ---</p>
      </div>
      <div class="chat-content">
        <div class="header">
          <div class="pic">
            <img src="@/assets/images/app/avatar.png" alt="" />
          </div>
          <p class="name">短语音生成工具</p>
        </div>
        <div class="chat" ref="chat">
          <div class="chat-list">
            <div v-for="(item) in historyList" :key="item.uuid">
              <!-- 系统提示 -->
              <div v-if="item.source === 'tip'" class="sys-tip">
                <p v-if="item.type === 'normal'" class="normal">{{ item.message }} {{ item.time }}</p>
                <p v-if="item.type === 'warning'" class="warning">{{ item.message }} {{ item.time }}</p>
              </div>
              <!-- 左侧消息 -->
              <div v-if="item.source === 'sys'" class="chat-content-left">
                <div class="pic">
                  <img src="@/assets/images/app/avatar.png" alt="" />
                </div>
                <div class="content">
                  <p class="name">{{ chatName }}</p>
                  <div class="content" @click="function(){
                    playAudio(item.message)
                  }" data-type="voice" ><i class="el-icon-video-play"></i>语音</div>
                  <i class="time">{{ item.time }}</i>
                </div>
              </div>
              <!-- 右侧消息 -->
              <div v-if="item.source === 'user'" class="chat-content-right">
                <div class="pic">
                  <img src="@/assets/images/app/avatar.png" alt="" />
                </div>
                <div class="content">
                  <p class="name">我</p>
                  <div class="content">{{ item.message }}</div>
                  <i class="time">{{ item.time }}</i>
                </div>
              </div>
            </div>
            <!-- <div class="sys-tip">
              <p class="normal">系统提示-普通提示 09:40:30</p>
              <p class="warning">系统提示-警告 09:40:30</p>
            </div> -->

            <!-- <div class="chat-content-left">
              <div class="pic">
                <img src="@/assets/images/app/avatar.png" alt="" />
              </div>
              <div class="content">
                <p class="name">短语音生成工具</p>
                <div class="content" @click="function(){
                  playAudio('http://tsn.baidu.com/text2audio?tex=%25E6%25B5%258B%25E8%25AF%2595%25E7%259F%25AD%25E8%25AF%25AD%25E9%259F%25B3%25E7%2594%259F%25E6%2588%2590&per=0&spd=3&pit=7&vol=6&aue=3&cuid=fef005e22db89d7382aeeeb3f9680040&tok=24.2df9fc1dae1128fb7ac429968cf92fd4.2592000.1718012014.282335-14733373&lan=zh&ctp=1')
                }" data-type="voice" ><i class="el-icon-video-play"></i>语音</div>
                <i class="time">09:40:53</i>
              </div>
            </div> -->
            <!-- <div class="chat-content-right">
              <div class="pic">
                <img src="@/assets/images/app/avatar.png" alt="" />
              </div>
              <div class="content">
                <p class="name">短语音生成工具</p>
                <div class="content">文字</div>
                <i class="time">09:40:53</i>
              </div>
            </div> -->
          </div>
        </div>
        <div class="editor">
          <div class="textarea">
            <el-input
              type="textarea"
              placeholder="请输入要发送的文字（全中文）"
              v-model.trim="chatMessage"
              resize="none"
              :show-word-limit="true"
              maxlength="40"
            ></el-input>
          </div>
          <div class="submit" @click="sendMessage">
            发送
          </div>
        </div>
      </div>
    </div>

    <!-- 隐藏音频播放 -->
    <audio style="position:absloute;top;0;left:0;" ref="audio" @pause="audioEnd" @ended="audioEnd" :src="audioSrc"></audio>
  </div>
</template>

<script>
import { Message } from 'element-ui'

export default {
  name: 'IM',
  mounted () {
    // 连接websocket服务器
    this.connectWs()
  },
  data () {
    return {
      audioPlay: false,
      audioSrc: '',
      tapList: [{
        name: '短语音生成工具'
      }],
      chatName: '短语音生成工具',
      // 历史数据
      historyList: [
        // {
        //   // 消息
        //   message: '2024-05-14',
        //   // 时间
        //   time: '',
        //   // 类型 : normal|warning|voice
        //   type: 'normal',
        //   // 消息源 user或者sys
        //   source: 'tip',
        //   uuid: '4'
        // },
        // {
        //   // 消息
        //   message: '消息',
        //   // 时间
        //   time: '12:12:22',
        //   // 类型 : normal|voice
        //   type: 'normal',
        //   // 消息源 user或者sys
        //   source: 'user',
        //   uuid: '1'
        // },
        // {
        //   // 消息
        //   message: '语音',
        //   // 时间
        //   time: '12:12:22',
        //   // 类型 : voice
        //   type: 'voice',
        //   // 消息源 user或者sys
        //   source: 'sys',
        //   uuid: '2'
        // },
        // {
        //   message: '系统提示',
        //   time: '12:12:24',
        //   type: 'warning',
        //   source: 'tip',
        //   uuid: '3'
        // }
      ],
      ws: null,
      chatMessage: '',
      fisrtSend: true
    }
  },
  methods: {
    // 音频播放完成方法
    audioEnd () {
      this.audioPlay = false
    },
    // 音频播放点击方法
    playAudio (url) {
      // 需要判断当前播放的音频是不是老的 如果是老的说明是相同按钮再次点击
      // 如果是不同的说明是点的另外一个音频
      // 还需要音频是否播放完成 播放未完成则暂停 播放完成则重新播放
      // el-icon-loading  el-icon-video-play
      const audioRef = this.$refs.audio
      if (url !== this.audioSrc) {
        this.audioSrc = url
        // 这里有dom操作所以要用nextTick不然会报错
        this.$nextTick(() => {
          audioRef.pause()
          audioRef.currentTime = 0
          audioRef.play()
          this.audioPlay = true
        })
      } else {
        if (this.audioPlay) {
          audioRef.pause()
          this.audioPlay = false
        } else {
          audioRef.currentTime = 0
          audioRef.play()
          this.audioPlay = true
        }
      }
    },
    // 连接websocket方法
    connectWs () {
      this.ws = new WebSocket('ws://' + process.env.VUE_APP_WEBSOCKET_URL + '/?type=tts&token=' + this.$store.state.user.userInfo.token
      )
      // this.ws.onopen = (event) => {
      //   this.showMessage('连接websocket服务器成功！', 'tip', 'normal')
      // }
      this.ws.onerror = (event) => {
        this.showMessage('连接websocket服务器失败！', 'tip', 'warning')
        this.ws = null
      }
      this.ws.onmessage = (event) => {
        this.dealWsMessage(event.data)
      }
      this.ws.onclose = (event) => {
        this.showMessage('websocket连接已断开！', 'tip', 'warning')
        this.ws = null
      }
    },
    // 根据类型处理数据方法
    dealWsMessage (data) {
      data = JSON.parse(data)
      // 排除掉心跳检测的方法
      if (data.mode && data.mode === 'heart') return
      // 不同类型进行处理 ['normal', 'warning', 'tip', 'voice', 'history'];
      const res = data.data
      if (data.type) {
        switch (data.type) {
          case 'normal':
            // 普通消息直接显示
            this.showMessage(res.message, res.source, 'normal', res.time)
            break
          case 'tip':
            // 提示信息直接显示
            this.showMessage(data.message, 'tip', 'normal')
            break
          case 'warning':
            // 错误提示
            this.showMessage(data.message, 'tip', 'warning')
            break
          case 'voice':
            // 语音消息需要做两件事
            // 1 增加发送消息的时间(sendId-uuid进行绑定)
            // res.sendId
            // res.message_data
            // res.voice_data
            this.bindTimeByUuid(res.sendId, res.message_data.time)
            // 2 增加语音消息数据
            this.showMessage(res.voice_data.message, 'sys', 'voice', res.voice_data.time)
            break
          case 'history':
            // 历史消息显示 暂时只有语音生成工具
            if (data.data[0] && data.data[0].list) {
              // 处理数据
              // tip类型
              // this.showMessage(res.voice_data.message, 'tip', 'normal')
              // voice类型
              // normal类型
              data.data[0].list.forEach((value) => {
                this.showMessage(value.message, value.source, value.type, value.time)
              })
              this.showMessage('以上为历史消息', 'tip', 'normal')
            }
            break
          default:
            break
        }
      }
    },
    // 根据消息的uuid绑定时间
    bindTimeByUuid (uuid, time) {
      this.historyList.forEach((value, index) => {
        if (value.uuid === uuid) {
          this.historyList[index].time = time
        }
      })
    },
    // 显示数据方法 只用写两种其他都是后端返回的 一种是系统提示 一种是自己发的消息，没显示时间的那种
    showMessage (message, source, type, time = '') {
      const uuid = this.createUuid()
      const data = {
        // 消息
        message: message,
        // 时间
        time: time,
        // 类型 : normal|voice|warning
        type: type,
        // 消息源 user或者sys或者tip
        source: source,
        uuid: uuid
      }
      this.historyList.push(data)
      // 滚动条操作
      this.changeChatHeight()
      return uuid
    },
    // 点击发送方法
    sendMessage () {
      if (!this.ws) {
        Message.error({
          message: '未连接到websocket服务器',
          duraton: 2000,
          showClose: true
        })
        return
      }
      // 首次发送消息显示一下时间
      if (this.fisrtSend) {
        this.fisrtSend = false
      }
      let errorMsg = ''
      if (!this.chatMessage) {
        errorMsg = '发送的信息不能为空'
      } else if (!/^[\u4e00-\u9fa5]+$/.test(this.chatMessage)) {
        errorMsg = '请输入全中文'
      }
      if (errorMsg) {
        Message.error({
          message: errorMsg,
          duraton: 2000,
          showClose: true
        })
        return
      }
      // 显示用户发送了信息
      const uuid = this.showMessage(this.chatMessage, 'user', 'normal')
      // 向服务器请求信息
      const sendData = this.createSendData(this.chatMessage, 'tts', uuid)
      this.ws.send(sendData)
      // 将文字设置为空
      this.chatMessage = ''
    },
    // 生成send数据方法
    createSendData (message, type, sendId) {
      const sendData = {
        type: type,
        message: message,
        sendId: sendId
      }
      return JSON.stringify(sendData)
    },
    // 生成uuid方法 仅用于标识
    createUuid () {
      const s = []
      const hexDigits = '0123456789abcdef'
      for (let i = 0; i < 36; i++) {
        s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1)
      }
      s[14] = '4' // bits 12-15 of the time_hi_and_version field to 0010
      s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1) // bits 6-7 of the clock_seq_hi_and_reserved to 01
      s[8] = s[13] = s[18] = s[23] = '-'

      const uuid = s.join('')
      return uuid
    },
    // 获取div高度 自动变更高度
    changeChatHeight () {
      this.$nextTick(() => {
        if (this.$refs.chat) {
          this.$refs.chat.scrollTop = this.$refs.chat.scrollHeight
        }
      })
    }

  }
}
</script>
<style lang="less" scoped>
.chat-background {
  position: absolute;
  width: 100%;
  height: calc(100% - 50px);
  z-index: 0;
  background-color: rgb(207, 204, 221);
}

.chat-box {
  position: absolute;
  background-color: rgb(242, 242, 244);
  left: 50%;
  top: 50%;
  width: 930px;
  height: 630px;
  transform: translate(-50%, -50%);
  box-shadow: 3px 3px 10px 0px rgb(61, 57, 57);
  // 30 + 200 + 700
  display: flex;

  .bar {
    width: 20px;
    background-color: rgb(55, 48, 126);
  }

  .left {
    width: 250px;
    padding: 20px 12px 20px 12px;
    user-select: none;
    border-right: 1px solid #e7e7e7;

    .title {
      color: rgb(21, 19, 32);
      font-size: 18px;
      font-weight: bold;
      letter-spacing: 2px;

      .tip {
        letter-spacing: 0px;
        position: relative;
        top: -1px;
        display: inline-block;
        font-size: 12px;
        line-height: 18px;
        width: 18px;
        height: 18px;
        border-radius: 50%;
        color: white;
        background-color: rgb(217, 46, 36);
        text-align: center;
      }
    }

    .list {
      padding-top: 15px;
      height: 570px;

      .card {
        display: flex;
        padding: 10px 10px;
        width: 100%;
        height: 60px;
        background-color: white;
        overflow: hidden;
        align-items: center;
        position: relative;

        .pic {
          width: 34px;
          height: 34px;
          border-radius: 50%;
          overflow: hidden;

          img {
            width: 34px;
            height: 34px;
          }
        }

        .content {
          width: 140px;
          margin-left: 10px;
          text-align: left;
          cursor: pointer;

          .name {
            width: 100%;
            font-size: 16px;
            color: rgb(55, 48, 126);
            font-weight: bold;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
          }

          .message {
            width: 100%;
            margin-top: 3px;
            font-size: 14px;
            color: rgb(174, 180, 177);
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
          }
        }

        .tip {
          width: 20px;

          .time {
            position: absolute;
            top: 8px;
            right: 5px;
            font-size: 12px;
            color: rgb(174, 180, 177);
          }

          .num {
            position: absolute;
            bottom: px;
            right: 5px;
            width: 16px;
            height: 16px;
            line-height: 16px;
            border-radius: 50%;
            font-size: 10px;
            color: white;
            background-color: rgb(217, 46, 36);
            text-align: center;
          }
        }
      }

      .card:hover {
        background-color: rgb(55, 48, 126);
        .content {
          .name {
            color: white;
          }
          .message {
            color: white;
          }
        }
        .tip {
          .time {
            color: white;
          }
          .num {
            background: white;
            color: rgb(55, 48, 126);
          }
        }
      }
    }
  }

  .chat-none {
    width: 660px;

    p {
      text-align: center;
      line-height: 630px;
      color: #979797;
      user-select: none;
    }
  }

  .chat-content {
    flex: 1;
    background-color: #f5f5f5;

    .header {
      width: 100%;
      height: 50px;
      border-bottom: 1px solid #e7e7e7;
      overflow: hidden;
      display: flex;
      padding: 12px 15px;

      .pic {
        width: 26px;
        height: 26px;
        border-radius: 50%;
        overflow: hidden;

        img {
          width: 100%;
          height: 100%;
        }
      }

      .name {
        padding-left: 5px;
        line-height: 26px;
        font-size: 16px;
        font-weight: bolder;
        color: rgb(55, 48, 126);
      }
    }

    .chat {
      padding: 15px;
      width: 100%;
      height: 480px;
      overflow-y: auto;
      border-bottom: 1px solid #e7e7e7;

      .chat-list {
        .sys-tip {
          text-align: center;
          font-size: 12px;

          .normal {
            margin-bottom: 10px;
            color: #979797;
          }

          .warning {
            margin-bottom: 10px;
            color: #ff1919;
          }
        }

        .chat-content-left,
        .chat-content-right {
          display: flex;
          margin-bottom: 10px;
        }

        .pic {
          width: 22px;
          height: 22px;
          border-radius: 50%;
          overflow: hidden;

          img {
            width: 100%;
            height: 100%;
          }
        }

        .content {
          position: relative;
          padding-left: 5px;

          .name {
            font-size: 12px;
            color: #979797;
            width: 100px;
            margin-right: 50px;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
          }

          .content {
            margin-top: 5px;
            font-size: 16px;
            padding: 10px;
            background-color: white;
            box-shadow: 1px 1px 5px 1px #e7e7e7;
            border-radius: 8px;
            border-top-left-radius: 0px;

            &[data-type="voice"] {
              cursor: pointer;
              padding-left: 40px;
              i {
                position: absolute;
                left: 10px;
                top: 10px;
                margin-right: 5px;
                font-size: 18px;
              }

              &:hover {
                color: rgb(55, 48, 126);
              }
            }
          }

          .time {
            position: absolute;
            width: 20px;
            height: 20px;
            right: 30px;
            top: 0px;
            font-size: 12px;
            color: #979797;
          }
        }

        .chat-content-right {
          flex-direction: row-reverse;

          .content {
            .name {
              height: 20px;
              width: 100px;
              line-height: 20px;
              margin-left: 50px;
              text-align: right;
              margin-right: 0;
              padding-right: 5px;
            }

            .time {
              position: absolute;
              left: 5px;
              top: 5px;
            }

            .content {
              border-radius: 8px;
              border-top-right-radius: 0px;
              padding-top: 10px;
            }
          }
        }
      }
    }

    .editor {
      padding: 20px 15px;
      position: relative;

      .textarea {
        padding-right: 65px;
      }
      .submit {
        position: absolute;
        right: 15px;
        top: 20px;
        height: 54px;
        width: 60px;
        border: 1px solid #e7e7e7;
        text-align: center;
        line-height: 54px;
        background-color: rgba(55, 48, 126, 0.9);
        color: white;
        border-radius: 5px;
        cursor: pointer;

        &:hover {
          background-color: rgba(55, 48, 126);
        }
      }
    }
  }
}
</style>
